/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.lang;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 */
public class EnumeRegistry {
    
    private final Map<Class<? extends Enume<?>>, EnumeInfo<? extends Enume<?>>> infos;
    
    public EnumeRegistry(EnumeConfigure configure) {
        infos = new HashMap<>();
    
        EnumeConfigurator configurator = new EnumeConfigurator() {
            @Override
            public <T extends Comparable<T>, E extends Enume<T>> TableColumnRegister enume(Class<E> enumeClass) {
                Enume.verifyEnumeClass(enumeClass);
                if (infos.containsKey(enumeClass)) {
                    throw new RuntimeException("The enume already registered! " + enumeClass);
                }
                EnumeInfo<? extends Enume<?>> info = new EnumeInfo<>(enumeClass);
                infos.put(enumeClass, info);
                return new TableColumnRegisterImpl(info);
            }
        };
        configure.configure(configurator);
    }
    
    public Collection<Class<? extends Enume<?>>> getEnumeClasses() {
        return infos.keySet();
    }
    
    public Collection<EnumeInfo<? extends Enume<?>>> getEnumeInfos() {
        return infos.values();
    }
    
    /**
     *
     */
    public interface EnumeConfigure {
        void configure(EnumeConfigurator conf);
    }
    
    /**
     *
     */
    public interface EnumeConfigurator {
        <T extends Comparable<T>, E extends Enume<T>> TableColumnRegister enume(Class<E> enumeClass);
    }
    
    /**
     *
     */
    public interface ColumnRegister {
        TableRegister column(String... columns);
    }
    
    /**
     *
     */
    public interface TableRegister {
        ColumnRegister table(String table);
    }

    /**
     *
     */
    public interface TableColumnRegister extends ColumnRegister, TableRegister {
    }
    
    /**
     *
     */
    private static class TableColumnRegisterImpl implements TableColumnRegister {
    
        private final EnumeInfo info;
        private String table;
    
        private TableColumnRegisterImpl(EnumeInfo info) {
            this.info = info;
        }
    
        @Override
        public ColumnRegister table(String table) {
            this.table = table;
            return this;
        }

        @Override
        public TableRegister column(String... columns) {
            info.tableColumns.add(new TableColumn(table, columns));
            return this;
        }
        
    }

    /**
     *
     */
    public static final class TableColumn {
        
        private final String table;
        private final List<String> columns;
    
        private TableColumn(String table, String... columns) {
            this.table = table;
            this.columns = Arrays.asList(columns);
        }
    
        public String getTable() {
            return table;
        }
    
        public List<String> getColumns() {
            return columns;
        }
    }
    
    /**
     *
     * @param <E>
     */
    public static final class EnumeInfo<E extends Enume<? extends Comparable<?>>> {
        
        private final Class<E> enumeClass;
        private final List<TableColumn> tableColumns;
    
        private EnumeInfo(Class<E> enumeClass) {
            this.enumeClass = enumeClass;
            this.tableColumns = new ArrayList<>();
        }
    
        public Class<E> getEnumeClass() {
            return enumeClass;
        }
    
        public List<TableColumn> getTableColumns() {
            return Collections.unmodifiableList(tableColumns);
        }
    }
}
